<?php
/**
 * File:	hook.inc.php
 * Purpose:	Code for implementing hooks and module control
 * Authors:	Gyrbo <dennis@gyrbo.be>
 *          EdG <edgray@vxcomputers.com>
 */

global $hooks;
$hooks = array();

function register_hook($hook, $function, $weight=0) {
	//global hooks array
	global $hooks;

	// If the function we were sent is not callable log it and end
	if(!is_callable($function)) {
		webcp_log(2, '', 'hook.inc.phps', '"'.$function.'" cannot be registered for the hook "'.$hook.'"', 'hook.inc.phps');
		return false;
	}

	// create new array within hooks array for this hook or add function
	//  to existing array....
	// e.g. $hooks['server:monitor:check'][0][] would make a new array item
	// for this function for that hook if the hook already exists
	$hooks[$hook][$weight][] = $function;

	return true;
}

function call_hook($hook, &$data) {
	global $hooks;
	$ret = array();
	// check if hook exists
	if(isset($hooks[$hook])) {
		// for each hook in the array
		// sort them into order by weight (so we know which fucntions to call first etc)
		foreach($hooks[$hook] as $w => $val) {
			$weights[] = $w;
			sort($weights);
		}
		// now go through weights array and hooks array and
		// if a function for a hook is callable call it
		// getting the return value
		foreach($weights as $w) {
			foreach($hooks[$hook][$w] as $f) {
				if (is_callable($f)) {
					$ret[] = $f($data);
				}
			}
		}
	}

	return $ret;
}

// load all modules that are in the db
function load_modules() {
	global $cfg, $hooks;

	//Clear existing hooks
	$hooks = array();

	if ($res = @mysql_query('SELECT `file` FROM `modules` WHERE `state` = 1')) {
		while($ar = mysql_fetch_array($res)) {
			$modfile = $cfg['basedir'].'/modules/'.$ar['file'];
			// Convert filename to def filename
			$modfile_def = str_replace('.mod.phps', '.def.phps', $modfile);

			// Set action for def file to run
			$action = 'hook';
			// Include module body file to define functions
			include_once($modfile);
			// Include module definition file to register hooks
			include($modfile_def);
		}
	}
}

// list modules that are registered (in the database)
function list_modules() {
	$ret = array();
	$res = mysql_query('SELECT `file`, `name`, `descr`, `state` FROM `modules`');
	while($ar = mysql_fetch_assoc($res)) {
		$ret[] = $ar;
	}

	return $ret;
}

// check if a module is registered
function is_registered($file) {
	$res = mysql_query('SELECT `file` FROM `modules` WHERE `file`="'.$file.'"');
	$result = mysql_num_rows($res);
	if ($result > 0)
		return true;
	else
		return false;
}

// check if a module is enabled
function is_enabled($file) {
	$res = mysql_query('SELECT `state` FROM `modules` WHERE `file`="'.$file.'" AND `state`=1');
	$result = mysql_num_rows($res);
	if ($result > 0)
		return true;
	else
		return false;
}

/*
Check Dependencies - Returns true if an action is possible
 $file_name = module filename.
 $action = whether trying to register or unregister a module
*/
function check_dependencies($file, $action) {
	// Convert file name to module name
	$module_name = str_replace('.mod.phps', '', $file);

	// Decide what to check - dependencies or exclusions
	if ($action == 'register' || $action == 'enable') {
		$check = 'exclusions';
	} elseif ($action == 'unregister' || $action == 'disable') {
		$check = 'dependencies';
	}
	// Check if anything excludes or depends on this module
	if ($action == 'register' || $action == 'unregister')
		$res = mysql_query('SELECT `'.$check.'` FROM `modules` WHERE `'.$check.'`!=""');
	elseif ($action == 'enable' || $action == 'disable')
		$res = mysql_query('SELECT `'.$check.'`, `state` FROM `modules` WHERE `'.$check.'`!="" AND `state`=1');
	$result = mysql_num_rows($res);

	// If there are modules check if they exclude or depend on the one we are looking for
	if ($result > 0) {
		for ($n = 0; $issues = mysql_fetch_array($res); $n++) {
			// Check if module is in the list of exclusions or dependencies
			if (stristr($issues[$check], $module_name)) {
				// Return false because goes against requirement to perform action
				return false;
			}
		}
	}
	// Return whether we can perform requested action
	return true;
}

// Solve module dependency issues.
function fix_dependencies($file, $module, $action) {
	// Check if action is possible
	if (!check_dependencies($file, $action))
		return false;
	// Perform requested action
	switch ($action) {
		case 'register':
			// Register module dependencies
			foreach($module['depends'] as $value) {
				if (!register_module($value.'.mod.phps'))
					return false;
			}
			// Unregister module exclusions.
			foreach($module['excludes'] as $value) {
				if (!unregister_module($value.'.mod.phps'))
					return false;
			}
			break;
		case 'enable':
			// Enable module dependencies
			foreach($module['depends'] as $value) {
				if (!enable_module($value.'.mod.phps'))
					return false;
			}
			// Disable module exclusions
			foreach($module['excludes'] as $value) {
				if (!disable_module($value.'.mod.phps'))
					return false;
			}
			break;
	}
	return true;
}

// Register modules ready to be loaded if enabled
function register_module($file) {
	global $cfg;
	unset($module);
	// If module is already registered nothing to do
	//  return true so that calling process knows module
	//  is registered
	if (is_registered($file)) {
		return true;
	}
	$module = array('name' => 'Noname', 'description' => '', 'depends' => Array(), 'excludes' => Array());

	// Replace module file name with module definition file name
	$module_def = str_replace('.mod.phps', '.def.phps', $file);

	// Set action so that nothing happens.
	$action = '';

	// Include module definition file
	include($cfg['basedir'].'/modules/'.$module_def);

	// Check if this module can be registered - is it excluded
	if (!fix_dependencies($file, $module, 'register'))
		return false;

	$SQL = 'INSERT INTO `modules` (`file`, `name`, `descr`, `state`, `dependencies`, `exclusions`) VALUES ("'.$file.'", "'.$module['name'].'", "'.$module['description'].'", 0, "'.((is_array($module['depends'])) ? implode(' ', $module['depends']) : '').'", "'.((is_array($module['excludes'])) ? implode(' ', $module['excludes']) : '').'")';
	$res = mysql_query($SQL);

	if($res) {
		// Set action for def file to perform
		$action = 'register';
		// Include def file again to run register code
		include($cfg['basedir'].'/modules/'.$module_def);
	}

	return $res;
}

// unregister a module from the database
function unregister_module($file) {
	global $cfg;
	unset($module);
	// If module is not already registered nothing to do
	//  return true so that calling process knows module
	//  is not registered
	if (!is_registered($file)) {
		return true;
	}
	$module = array('name' => 'Noname', 'description' => '', 'depends' => Array(), 'excludes' => Array());

	// Replace module file name with module definition file name
	$module_def = str_replace('.mod.phps', '.def.phps', $file);

	// Set action so that nothing happens.
	$action = '';

	// Include module definition file
	include($cfg['basedir'].'/modules/'.$module_def);

	// Check if this module can be unregistered - is anything dependant on it
	if (!fix_dependencies($file, $module, 'unregister'))
		return false;

	$res = mysql_query('DELETE FROM `modules` WHERE `file` = "'.$file.'"');

	if($res) {
		// Set action for def file to perform
		$action = 'unregister';
		// Include def file again to run unregister code
		include($cfg['basedir'].'/modules/'.$module_def);
	}

	return $res;
}

function enable_module($file) {
	global $cfg;
	unset($module);
	// If module is already enabled we have nothing to do
	//  return true so that calling process knows module
	//  is enabled
	if (is_enabled($file)) {
		return true;
	}
	$module = array('name' => 'Noname', 'description' => '', 'depends' => Array(), 'excludes' => Array());

	// Replace module file name with module definition file name
	$module_def = str_replace('.mod.phps', '.def.phps', $file);

	// Set action so that nothing happens.
	$action = '';

	// Include module definition file
	include($cfg['basedir'].'/modules/'.$module_def);

	// Check if this module can be enabled - is it excluded
	if (!fix_dependencies($file, $module, 'enable'))
		return false;

	$res = mysql_query('UPDATE `modules` SET `state` = 1 WHERE `file` = "'.$file.'"');

	if($res) {
		// Set action for def file to perform
		$action = 'enable';
		// Include def file again to run enable code
		include($cfg['basedir'].'/modules/'.$module_def);
	}

	return $res;
}

function disable_module($file) {
	global $cfg;
	unset($module);
	// If module is not already enabled we have nothing to do
	//  return true so that calling process knows module
	//  is not enabled
	if (!is_enabled($file)) {
		return true;
	}
	$module = array('name' => 'Noname', 'description' => '', 'depends' => Array(), 'excludes' => Array());

	// Replace module file name with module definition file name
	$module_def = str_replace('.mod.phps', '.def.phps', $file);

	// Set action so that nothing happens.
	$action = '';

	// Include module definition file
	include($cfg['basedir'].'/modules/'.$module_def);

	// Check if this module can be disabled - is anything dependant on it
	if (!fix_dependencies($file, $module, 'disable'))
		return false;

	$res = mysql_query('UPDATE `modules` SET `state` = 0 WHERE `file` = "'.$file.'"');

	if($res) {
		// Set action for def file to perform
		$action = 'disable';
		// Include def file again to run disable code
		include($cfg['basedir'].'/modules/'.$module_def);
	}

	return $res;
}

function get_property($name, $id, $user=NULL) {
	$SQL = 'SELECT `value` FROM `properties` WHERE `id` = "'.$id
		.'" AND `user` = '.(is_null($user)?'NULL':'"'.$user.'"')
		.' AND `name` = "'.$name.'" LIMIT 1';
	if ($res = mysql_query($SQL)) {
		if(mysql_num_rows($res) > 0 && $ar = mysql_fetch_row($res)) {
			return $ar[0];
		}
	}
	return NULL;
}

function set_property($name, $value, $id, $user=NULL) {
	$SQL = 'INSERT INTO `properties` (`id`, `user`, `name`, `value`) '
		.'VALUES ("'.$id.'", '.(is_null($user)?'NULL':'"'.$user.'"').', "'.$name
		.'", "'.$value.'")';
	$res = mysql_query($SQL);

	if(!$res) {
		$res = mysql_query('UPDATE `properties` SET `value` = "'.$value.'" WHERE '
			.'`id` = "'.$id.'" AND `user` = '.(is_null($user)?'NULL':'"'.$user.'"')
			.' AND `name` = "'.$name.'" LIMIT 1');

		if(!$res) {
			return false;
		}
	}

	return true;
}

?>
